﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FacturIT.BLL.Model;
using FacturIT.BLL.Model.Helper;
using System.Data.Linq;
using System.IO;

namespace FacturIT.Service
{
    public abstract class IRepository<T,Tid>
    {
        private DataContext db;
        protected DataContext DB { get {
            db.Log = Console.Out;
            return db; } 
            set { db = value; } }
        public abstract T Read(Tid id);
        public abstract IEnumerable<T> ReadAll();

        public IEnumerable<T> ReadAll(IDictionary<Func<T, object>, Enum.Ordering> order)
        {
            return ApplyOrdering(ReadAll(), order);
        }
        public abstract IEnumerable<T> ReadAll(params Tid[] ids);
        public IEnumerable<T> ReadAll(Tid[] ids, IDictionary<Func<T, object>, Enum.Ordering> columns)
        {
            return ApplyOrdering(ReadAll(ids), columns);
        }

        public abstract T Add(T t);


        public bool Delete(Tid id)
        {
            Delete(ReadByID(id));
            return !Exists(id);
        }

        public abstract bool Delete(T id);
        public abstract T Update(T t);

        public T Duplicate(Tid id)
        {
            return Duplicate(ReadByID(id));
        }

        public abstract T Duplicate(T t);

        public void SaveChanges()
        {
            db.SubmitChanges();
        }

        public bool Exists(Tid id) { 
            return ReadByID(id) != null;
        }
        public bool AnyExists(params Tid[] ids)
        {
            bool anyExists = false;
            foreach (var id in ids)
            {
                if (!anyExists)
                    anyExists = ReadByID(id) != null;
            }
            return anyExists;
        }
        public bool AllExists(params Tid[] ids)
        {
            bool allExists = false;
            if (ids.Length > 0) allExists = true;

            foreach (var id in ids)
            {
                if(allExists) allExists = ReadByID(id) != null;
            }
            return allExists;
        }


        public int Count() {
            return Enumerable.Count(ReadAll());
        }

        protected abstract T ReadByID(Tid id);
        protected abstract void UpdateObject(T t, T oriT, bool replaceID);
        protected abstract IEnumerable<T> ApplyOrdering(IEnumerable<T> query, IDictionary<Func<T, object>, Enum.Ordering> columns);
        
        protected int Count(IEnumerable<T> query)
        {
            return Enumerable.Count(query);
        }
        protected IEnumerable<T> Distinct(IEnumerable<T> query)
        {
            return Enumerable.Distinct(query);
        }

        /// <summary>
        /// reads the first result of a query
        /// </summary>
        /// <param name="query"></param>
        /// <returns>null if empty</returns>
        protected T First(IEnumerable<T> query)
        {
            return query.FirstOrDefault();
        }
        /// <summary>
        /// Randomizes a list
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        protected IEnumerable<T> Randomize(IEnumerable<T> query)
        {
            Random rnd = new Random();
            
            return from item in query orderby rnd.Next() select item;
        }

        /// <summary>
        /// Gets the first x results
        /// </summary>
        /// <param name="query"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        protected IEnumerable<T> Take(IEnumerable<T> query, int top)
        {
            return query.Take(top);
            
        }
        /// <summary>
        /// gets the results after limit
        /// </summary>
        /// <param name="query"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        protected IEnumerable<T> Set(IEnumerable<T> query, int skip)
        {
            return query.Skip(skip);
        }
        /// <summary>
        /// gets the x first result starting from limit
        /// </summary>
        /// <param name="query"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        protected IEnumerable<T> Set(IEnumerable<T> query, int skip, int top)
        {
            return query.Skip(skip).Take(top);
        }



    }
} 


